package com.zzs.common.security.util;

import com.zzs.common.core.constant.JwtConsts;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.time.Instant;
import java.util.Date;

/**
 * 封装jwt的工具类，但是具体跟登录相关的业务操作，请优先使用{@link com.zzs.common.security.service.TokenService}，它使用jwtUtil实现了更具体的业务逻辑
 * @author zzs
 * @date 2025/03/17
 */
@Component
public final class JwtProvider {
    @Value("${jwt.secret}")
    private String secret;

    private SecretKey secretKey;

    @PostConstruct
    public void init() {
        secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));
    }


    /**
     * 生成jwt
     * @param userId 用户id
     * @return 生成的jwt字符串
     */
    public  String createToken(Long userId) {
        return Jwts.builder()
                .claim(JwtConsts.USER_ID_KEY, userId)
                .issuedAt(Date.from(Instant.now()))
                .expiration(new Date(System.currentTimeMillis() + JwtConsts.TOKEN_EXPIRE_TIME))
                .signWith(secretKey, Jwts.SIG.HS256)
                .compact();
    }

    /**
     * 解析jwt, 获取用户id
     * @param token jwt字符串
     * @return 用户id
     */
    public  Long getUserId(String token) {
        try {
            return Jwts.parser()
                    .verifyWith(secretKey)
                    .build()
                    .parseSignedClaims(token)
                    .getPayload()
                    .get(JwtConsts.USER_ID_KEY, Long.class);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 判断jwt是否过期
     * @param token jwt字符串
     * @return true表示过期, false表示未过期
     */
    public  boolean isExpired(String token) {
        try {
            Date expiration = Jwts.parser()
                    .verifyWith(secretKey)
                    .build()
                    .parseSignedClaims(token)
                    .getPayload()
                    .getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
//            解析失败, 就认为过期
            return true;
        }
    }

    /**
     * 获取jwt的剩余有效时间(毫秒)
     * @param token jwt字符串
     * @return 剩余时间(毫秒), 如果已过期就返回0
     */
    public  long getRemainingTime(String token) {
        try {
            Date expiration = Jwts.parser()
                    .verifyWith(secretKey)
                    .build()
                    .parseSignedClaims(token)
                    .getPayload()
                    .getExpiration();
            return Math.max(0, expiration.getTime() - System.currentTimeMillis());
        } catch (Exception e) {
//            解析失败, 就认为过期, 剩余有效时间为0
            return 0;
        }
    }
}
